package cn.orangeframe.neon.application.mapper;

import cn.orangeframe.neon.application.exception.TerminateWorkflowException;
import cn.orangeframe.neon.application.run.evaluator.Evaluator;
import cn.orangeframe.neon.domain.entity.WorkflowTask;
import cn.orangeframe.neon.domain.enums.TaskStatus;
import cn.orangeframe.neon.domain.enums.TaskType;
import cn.orangeframe.neon.domain.model.TaskModel;
import cn.orangeframe.neon.domain.model.WorkflowModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

@Slf4j
@Component(TaskType.TASK_TYPE_SWITCH)
public class SwitchTaskMapper implements TaskMapper {

    private final Map<String, Evaluator> evaluators;

    public SwitchTaskMapper(Map<String, Evaluator> evaluators) {
        this.evaluators = evaluators;
    }

    @Override
    public String getTaskType() {
        return TaskType.TASK_TYPE_SWITCH;
    }

    @Override
    public List<TaskModel> getMappedTasks(TaskMapperContext taskMapperContext) throws TerminateWorkflowException {
        List<TaskModel> tasksToBeScheduled = new LinkedList<>();
        WorkflowModel workflowInstance = taskMapperContext.getWorkflowInstance();
        WorkflowTask workflowTask = taskMapperContext.getTaskToSchedule();
        Map<String, Object> taskInput = taskMapperContext.getTaskInput();
        int retryCount = taskMapperContext.getRetryCount();

        // get the expression to be evaluated
        String evaluatorType = workflowTask.getEvaluatorType();
        Evaluator evaluator = evaluators.get(evaluatorType);
        if (evaluator == null) {
            String errorMsg = String.format("No evaluator registered for type: %s", evaluatorType);
            log.error(errorMsg);
            throw new TerminateWorkflowException(errorMsg);
        }

        String evalResult;
        try {
            evalResult = "" + evaluator.evaluate(workflowTask.getExpression(), taskInput);
        } catch (Exception exception) {
            TaskModel switchTask = taskMapperContext.createTaskModel();
            switchTask.setTaskType(TaskType.TASK_TYPE_SWITCH);
            switchTask.setTaskDefName(TaskType.TASK_TYPE_SWITCH);
            switchTask.getInputData().putAll(taskInput);
            switchTask.setStartTime(System.currentTimeMillis());
            switchTask.setStatus(TaskStatus.FAILED);
            switchTask.setReasonForInCompletion(exception.getMessage());
            tasksToBeScheduled.add(switchTask);

            return tasksToBeScheduled;
        }

        TaskModel switchTask = taskMapperContext.createTaskModel();
        switchTask.setStatus(TaskStatus.IN_PROGRESS);
        tasksToBeScheduled.add(switchTask);

        List<WorkflowTask> selectedTasks = workflowTask.getDecisionCases().get(evalResult);
        if (selectedTasks == null || selectedTasks.isEmpty()) {
            // 如果没有指定case，则使用默认case
            selectedTasks = workflowTask.getDefaultCase();
        }
        if (selectedTasks != null && !selectedTasks.isEmpty()) {
            WorkflowTask selectedTask = selectedTasks.getFirst();
            List<TaskModel> caseTasks =
                    taskMapperContext
                            .getDeciderService()
                            .getTasksToBeScheduled(
                                    workflowInstance,
                                    selectedTask,
                                    retryCount);

            switchTask.getInputData().put("hasChildren", "true");
            tasksToBeScheduled.addAll(caseTasks);
        }
        return tasksToBeScheduled;
    }
}
